<template>
  <div class="pop-wrapper" ref="popup" @click="close">
    <div class="describe-wrapper" ref="describeWrapper">
      <div
        class="describe-line"
        ref="describeLine"
        v-for="(item, index) in textList"
        :key="index"
      >
        {{ item }}
      </div>
    </div>
  </div>
</template>

<script>
import { mapState, mapMutations } from 'vuex'
export default {
  name: 'poppup',
  props: ['param'],
  computed: {
    ...mapState('focus', ['carousel'])
  },
  data() {
    return {
      describe: '',
      funcList: [],
      descList: [],
      descIndex: 0,
      funcIndex: 0,
      partId: '',
      timer: null,
      voiceFlag: false,
      textIndex: 0,
      textList: [],
      splitNum: 50,
      waitIndexList: [],
      totalSpeakTime: 0,
      speakTimeList: [],
    }
  },
  methods: {
    ...mapMutations('focus', ['setCarousel']),
    show() {
      //监听路由切换，取消聚焦操作
      app.$on(app.EventType.pageLeave, this.pageLeave)

      let opt = {}
      Object.assign(opt, this.param)
      //没有配置描述则智能解说时自动跳过该组件
      if (!opt.describe) {
        if (this.carousel) {
          app.focusServer.hideComplete()
          app.focusServer.focuseNext()
          return
        }
      }
      //高亮组件
      this.$refs['popup'].style.display = 'block'
      this.partId = opt.id
      if (this.partId.indexOf(this.$route.name) != -1) {
        this.partId = this.partId.replace(`${this.$route.name}.`, '')
      }
      if (this.isPartId()) {
        app.actionServer.exec('partServer.highLight', {
          partId: this.partId,
          isActive: true
        })
      } else {
        app.actionServer.exec('partServer.highLight', {
          isActive: false
        })
      }
      if (!opt.describe) {
        return
      }
      //处理描述
      this.funcList = this.getFunc(opt.describe)
      let desc = this.getDesc(opt.describe)
      this.describe = desc.replace(/\$\$\$\$/g, '')
      this.descList = desc.split('$$$$').filter((item) => item != '')
      this.textList = []
      this.waitIndexList = []
      if (this.descList.length == 1 && this.describe.length > 50) {
        this.textList = this.breakStr(this.describe, this.splitNum, [])
      } else if (this.describe.length < 50) {
        this.textList.push(this.describe)
      } else {
        let i = -1
        this.descList.forEach((item) => {
          if (item.length < 50) {
            this.textList.push(item)
            i++
            this.waitIndexList.push(i)
          } else {
            this.textList = this.textList.concat(
              this.breakStr(item, this.splitNum, [])
            )
            i += this.breakStr(item, this.splitNum, []).length
            this.waitIndexList.push(i)
          }
        })
      }
      let option = app.voiceFeedbackServer.getOption()
      let rate = option?.rate || 1
      let speakSpeed =
        app.voiceFeedbackServer.synthesisType == 'default'
          ? 12.5 / 50 / rate
          : 11.5 / 50 / rate
      this.speakTimeList = []
      this.textList.forEach((item, index) => {
        let time = item.length * speakSpeed
        this.speakTimeList.push(time)
      })
      for (let i = 0; i < this.waitIndexList.length - 1; i++) {
        this.speakTimeList[this.waitIndexList[i]] += 1
      }
      this.totalSpeakTime = 0
      for (let i = 0; i < this.speakTimeList.length; i++) {
        this.totalSpeakTime += this.speakTimeList[i]
      }

      this.funcIndex = 0
      this.descIndex = 0
      this.textIndex = 0
      if (this.tl) this.tl = null
      this.tl = new TimelineMax({})
      let describeWrapper = TweenMax.fromTo(
        this.$refs['describeWrapper'],
        0.5,
        { opacity: 0, bottom: -60 },
        { opacity: 1, bottom: 20 }
      )
      this.tl
        .addLabel('start', 0)
        .add(() => {
          if (this.tl?.reversed()) return
          this.listTl()
        }, 'start+=0')
        .add(() => {
          if (
            this.tl?.reversed() &&
            this.$refs['describeWrapper'].style.opacity == 0
          )
            return

          describeWrapper
        }, 'start+=0.1')
        .add(() => {
          if (this.tl?.reversed()) return
          if (app.voiceFeedbackServer.state == true) {
            app.voiceFeedbackServer.queue = []
            app.voiceFeedbackServer.addEventListener('end', this.funcEvent)
            //判断描述最开始是否为$$方法,如果是则先exec,再speak
            if (opt.describe.indexOf('$$') == 0) {
              this.exec()
            }
            for (let i = 0; i < this.descList.length; i++) {
              app.voiceFeedbackServer.speak(this.descList[i])
            }
          }
        }, 'start+=0.3')
    },
    hide() {
      if (app.voiceFeedbackServer.state == true) {
        app.voiceFeedbackServer.queue = []
        app.voiceFeedbackServer.synthesis.cancel()
        app.voiceFeedbackServer.removeEventListener('end', this.funcEvent)
      }
      //取消组件高亮
      if(this.isPartId()) {
        if (!(this.carousel && app.focusServer.carouselNum != -1)) {
          app.actionServer.exec('partServer.highLight', {
            isActive: false
          })
        }
      }

      if (!this.param.describe) {
        this.$refs['popup'].style.display = 'none'
        app.focusServer.hideComplete()
        app.$off(app.EventType.pageLeave, this.pageLeave)
        // 自动轮播时 通知系统播放下一个
        if (this.carousel) {
          app.focusServer.focuseNext()
        }
        return
      }
      if (!this.tl) return
      this.tl.eventCallback('onReverseComplete', () => {
        this.tl.clear()
        this.tl.eventCallback('onReverseComplete', null)
        this.tl = null
        if(this.childTl) {
          this.childTl.eventCallback('onReverseComplete', null)
          this.childTl.clear()
          this.childTl = null
        }
        this.$refs['popup'].style.display = 'none'
        app.focusServer.hideComplete()
        app.$off(app.EventType.pageLeave, this.pageLeave)
        // 自动轮播时 通知系统播放下一个
        if (this.carousel) {
          app.focusServer.focuseNext()
        }
      })
      this.tl?.timeScale(3).reverse()
    },
    isPartId() {
      let allParts = app.config.page.pages.filter((item) => {
        return item.name == this.$route.name
      })[0]?.parts
      for (let i = 0; i < allParts.length; i++) {
        if (allParts[i].id == this.partId) {
          return true
        }
      }
      return false
    },
    pageLeave() {
      app.focusServer.inactivated()
      app.focusServer.carousel = false
    },
    listTl() {
      let y = 60
      let time = 0.5
      if (this.childTl) this.childTl = null
      this.childTl = new TimelineMax({})
      this.childTl.addLabel('start')
      this.$nextTick(() => {
        let describeLines = this.$refs['describeLine']
        let lines = {}
        let lines2 = {}
        let totalTime = 0
        for (let i = 0; i < describeLines.length; i++) {
          lines[`line${i + 1}`] = TweenMax.fromTo(
            describeLines[i],
            time,
            {
              opacity: 0,
              y: y
            },
            {
              opacity: 1,
              y: 0
            }
          )
          this.childTl.add(lines[`line${i + 1}`], 'start+=' + (totalTime + 0))
          totalTime += this.speakTimeList[i]
        }

        let totalTime2 = 0
        for (let i = 0; i < describeLines.length - 1; i++) {
          totalTime2 += this.speakTimeList[i]
          lines2[`line${i + 1}`] = TweenMax.to(describeLines[i], time, {
              opacity: 0,
              y: -y
            })
          this.childTl.add(lines2[`line${i + 1}`], 'start+=' + (totalTime2 - 0.2))
        }
        if (!this.carousel) {
          totalTime2 += this.speakTimeList[describeLines.length - 1]
          let lastLine = TweenMax.to(
            describeLines[describeLines.length - 1],
            time,
            {
              opacity: 1
            }
          )
          this.childTl.add(lastLine, 'start+=' + totalTime2)
          let describeWrapper = TweenMax.fromTo(
            this.$refs['describeWrapper'],
            0.5,
            { opacity: 1, bottom: 0 },
            { opacity: 0, bottom: -60, delay: 2 }
          )
          this.childTl.add(describeWrapper, 'start+=' + totalTime2)
        }
      })
      return this.childTl
    },
    funcEvent() {
      if (this.param.describe.indexOf('$$') != -1) {
        if (this.param.describe.indexOf('$$') != 0) {
          if (this.funcIndex < this.funcList.length) {
            this.exec()
            this.funcIndex++
          }
        } else {
          this.funcIndex++
          if (this.funcIndex < this.funcList.length) {
            this.exec()
          }
        }
      }
      this.descIndex++
      if (this.carousel && this.descIndex == this.descList.length) {
        app.voiceFeedbackServer.queue = []
        this.$nextTick(() => {
          this.timer = setTimeout(() => {
            this.endEvent()
          }, 1000)
        })
      }
    },
    endEvent() {
      if (this.timer) {
        clearTimeout(this.timer)
        this.timer = null
      }
      // 通知系统当前轮播组件结束
      app.focusServer.inactivated()
    },
    close() {
      if (!this.carousel) {
        app.focusServer.inactivated()
      }
      this.carousel && this.setCarousel(false)
    },
    exec() {
      if (!this.partId || !this.isPartId()) return
      const instance = app.partServer.getCompById(this.partId)
      if (instance) {
        const remoteList = instance?.$options?.propsData?.part?.remote
        if(remoteList && remoteList.length) {
          //获取配置中exec()方法中的所有参数，第一个参数必传，为选中值，第二个参数非必传，为组件中v-remote的索引值，默认是0
          let args = this.getParam(this.funcList[this.funcIndex])
          let remoteIndex = 0
          if(args && args.length > 1) {
            remoteIndex = parseInt(args[1])
          }
          let actionId = remoteList[remoteIndex]?.id
          if (actionId) {
            app.actionServer.exec(actionId, args[0])
          }
        }
      }
    },
    getDesc(desc) {
      let describe = desc
      for (let i = 0; i < this.funcList.length; i++) {
        describe = describe.replaceAll(this.funcList[i], '')
      }
      return describe
    },
    getFunc(desc) {
      let reg = /\$\$(.*?)\$\$/gi
      let tmp = desc.match(reg)
      let funcList = []
      if (tmp) {
        for (let i = 0; i < tmp.length; i++) {
          funcList.push(tmp[i].replace(reg, '$1')) // 不保留$$
        }
      }
      return funcList
    },
    getParam(func) {
      let reg = /\((.*?)\)/gi
      let tmp = func.match(reg)
      let param = tmp[0].replace(reg, '$1').split(',')
      return param
    },
    breakStr(str, step, receiver) {
      //str 需要截取的字符串
      //step 步长
      //receiver 接收器,是数组
      var remainder = str.length % step
      var n = (str.length - remainder) / step
      for (var i = 0; i <= n; i++) {
        receiver.push(str.slice(i * step, (i + 1) * step))
      }
      return receiver
    }
  }
}
</script>

<style lang="scss" scoped>
.pop-wrapper {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  z-index: 1000;
  display: none;
  transform-origin: center !important;
  .describe-wrapper {
    opacity: 0;
    display: flex;
    align-items: center;
    width: 978px;
    height: 60px;
    overflow: hidden;
    position: absolute;
    bottom: 20px;
    background: linear-gradient(
      to right,
      rgba(0, 0, 0, 0),
      rgba(0, 0, 0, 0.5),
      rgba(0, 0, 0, 0)
    );
    // backdrop-filter: blur(4px);
    left: 50%;
    transform: translateX(-50%);
    padding: 10px 20px;
    font-size: 16px;
    color: #c1fffb;
    .describe-line {
      width: calc(100% - 40px);
      position: absolute;
      display: flex;
      justify-content: center;
      align-items: center;
      line-height: 25px;
      text-align: center;
      letter-spacing: 1px;
    }
  }
}
</style>
